package componentes.mips;

import componentes.basicos.Palavra;
import java.util.ArrayList;

/**
 * Classe que faz a conversao de um minemonico para uma instrucao em binário correspondente.
 * 
 * @author Gustavo Miguel, Cleisson Alves, Evandro Francisco, Lucas.
 */
public class Instrucao {
    
    // Operacoes logicas aritmeticas: add, sub, and, or, slt.
    // Operacoes de Transferencia de dados: lw, sw.
    // Operacoes de Desvio: beq, j.
    
    public static String[] minemonico;                // Minemonico. 
    private static String tipo;                        // Tipo correspondente da instrucao.(J, R ou I).
    private static ArrayList<String[]> registradores;  // Registradores correspondentes em binario.   
    
    // Contrutor da classe
    public Instrucao() {
        minemonico = new String[3];
        tipo = new String();
        registradores = new ArrayList<String[]>();
        
    }
    
    /**
     * Método estático para pegar a representação em Palavra a partir 
     * de uma determinada instrução
     * @param instrucao Intrução 
     * @return Palavra correspondente.
     */
    public static Palavra getPalavra(String instrucao) {
        
        String palavra = ""; // Palavra inicialemente.
        setRegistradores();
        Instrucao.minemonico = instrucao.split(" ");
        
        if(minemonico[0].equals("add")) {
            // add $t0 $t0 $t0
            Instrucao.tipo = "R";
            palavra = palavra + "000000" + getBinarioRegistrador(minemonico[2]) + 
                      getBinarioRegistrador(minemonico[3]) + getBinarioRegistrador(minemonico[1]) + 
                      "00000100000";
                    
        } else
        
        if(minemonico[0].equals("sub")) {
            Instrucao.tipo = "R";
            palavra = palavra + "000000" + getBinarioRegistrador(minemonico[2]) + 
                      getBinarioRegistrador(minemonico[3]) + getBinarioRegistrador(minemonico[1]) + 
                      "00000100010";
        } else
        
        if(minemonico[0].equals("and")) {
            Instrucao.tipo = "R";
            palavra = palavra + "000000" + getBinarioRegistrador(minemonico[2]) + 
                      getBinarioRegistrador(minemonico[3]) + getBinarioRegistrador(minemonico[1]) + 
                      "00000100100";
        } else
        
        if(minemonico[0].equals("slt")) {
            Instrucao.tipo = "R";
            palavra = palavra + "000000" + getBinarioRegistrador(minemonico[2]) + 
                      getBinarioRegistrador(minemonico[3]) + getBinarioRegistrador(minemonico[1]) + 
                      "00000101010";
        } else
        
        if(minemonico[0].equals("or")) {
            Instrucao.tipo = "R";
            palavra = palavra + "000000" + getBinarioRegistrador(minemonico[2]) + 
                      getBinarioRegistrador(minemonico[3]) + getBinarioRegistrador(minemonico[1]) + 
                      "00000100101";
        } else
        
        if(minemonico[0].equals("lw")) {
            // lw $8, 100($t9)
            Instrucao.tipo = "LW";
            palavra = palavra + "100011" + getBinarioRegistrador(minemonico[2].substring(minemonico[2].length()-4, minemonico[2].length()-1))+
                      getBinarioRegistrador(minemonico[1]) + completaBits(Integer.toBinaryString(Integer.parseInt(minemonico[2].substring(0, minemonico[2].length()-5))),16);
        } else
        
        if(minemonico[0].equals("sw")) {
            Instrucao.tipo = "SW";
            palavra = palavra + "101011" + getBinarioRegistrador(minemonico[2].substring(minemonico[2].length()-4, minemonico[2].length()-1))+
                      getBinarioRegistrador(minemonico[1]) + completaBits(Integer.toBinaryString(Integer.parseInt(minemonico[2].substring(0, minemonico[2].length()-5))),16);
        } else
        
        if(minemonico[0].equals("beq")) {
            // beq $t0, $t1, 100
            Instrucao.tipo = "BEQ";
            palavra = palavra + "000100" + getBinarioRegistrador(minemonico[1]) + getBinarioRegistrador(minemonico[2]) + 
                    completaBits(Integer.toBinaryString(Integer.parseInt(minemonico[3])),16);
        } else
        
        {
            Instrucao.tipo = "J";
            palavra = palavra + "000010" + completaBits(Integer.toBinaryString(Integer.parseInt(minemonico[1])),26);
        } 
        
        return new Palavra(palavra);
    }

    /**
     * Retorna o tipo da intrução.
     * @return tipo da instrução.
     */
    public static String getTipo() {
        return tipo;
    }
    
    /**
     * Método estático que retorna os registradores em formatos de strings.
     * @return Representação dos registradores em Strings.
     */
    public static ArrayList<String[]> getRegistradores() {
        return registradores;
    } 
    
    
    /* Metodo privados */
    // Completa os bits na palavra
    private static String completaBits(String palavra, int qtdBits) {

        int limite = qtdBits - palavra.length();
        
        for(int i = 0; i < limite; ++i) {
            palavra = "0"+palavra;
        }
        
        return palavra;
        
    }
    
    // Pega o binario do registrador correspondente.
    private static String getBinarioRegistrador(String registrador) {
        
        for(int i = 0; i < registradores.size(); ++i) {
            
            if(registradores.get(i)[0].equals(registrador)) {
                return registradores.get(i)[1];
            }
            
        }
        
        System.out.println("Instrucao: Nao foi possivel encontrar um Binario Correspondete ao registrador.");
        return null;
        
    }
    
    // configura todos os registradores e seus respectivos binarios.
    private static void setRegistradores() {
        
        registradores = new ArrayList<String[]>();
        // Registrador zero 0.
        String[] regZero = {"$zero","00000"};
        registradores.add(regZero);
         
        // Registrador $at 1. 
        String[] regAt = {"$at","00001"};
        registradores.add(regAt);
        
        // Registrador $v0 2.
        String[] regV0 = {"$v0","00010"};
        registradores.add(regV0);
        
        // Registrador $v1 3.
        String[] regV1 = {"$v1","00011"};
        registradores.add(regV1);
        
        // Registrador $a0 4.
        String[] regA0 = {"$a0","00100"};
        registradores.add(regA0);
        
        // Registrador $a1 5.
        String[] regA1 = {"$a1","00101"};
        registradores.add(regA1);
        
        // Registrador $a2 6.
        String[] regA2 = {"$a2","00110"};
        registradores.add(regA2);
        
        // Registrador $a3 7.
        String[] regA3 = {"$a3","00111"};
        registradores.add(regA3);
        
        // Registrador $t0 8.
        String[] regT0 = {"$t0","01000"};
        registradores.add(regT0);
        
        // Registrador $v0 9.
        String[] regT1 = {"$t1","01001"};
        registradores.add(regT1);
        
        // Registrador $t2 10.
        String[] regT2 = {"$t2","01010"};
        registradores.add(regT2);
        
        // Registrador $t3 11.
        String[] regT3 = {"$t3","01011"};
        registradores.add(regT3);
        
        // Registrador $t4 12.
        String[] regT4 = {"$t4","01100"};
        registradores.add(regT4);
        
        // Registrador $t5 13.
        String[] regT5 = {"$t5","01101"};
        registradores.add(regT5);
        
        // Registrador $t6 14.
        String[] regT6 = {"$t6","01110"};
        registradores.add(regT6);
        
        // Registrador $t7 15.
        String[] regT7 = {"$t7","01111"};
        registradores.add(regT7);
        
        // Registrador $s0 16.
        String[] regS0 = {"$s0","10000"};
        registradores.add(regS0);
        
        // Registrador $s1 17.
        String[] regS1 = {"$s1","10001"};
        registradores.add(regS1);
        
        // Registrador $s2 18.
        String[] regS2 = {"$s2","10010"};
        registradores.add(regS2);
        
        // Registrador $s3 19.
        String[] regS3 = {"$s3","10011"};
        registradores.add(regS3);
        
        // Registrador $s4 20.
        String[] regS4 = {"$s4","10100"};
        registradores.add(regS4);
        
        // Registrador $s5 21.
        String[] regS5 = {"$s5","10101"};
        registradores.add(regS5);
        
        // Registrador $s6 22.
        String[] regS6 = {"$s6","10110"};
        registradores.add(regS6);
        
        // Registrador $s7 23.
        String[] regS7 = {"$s7","10111"};
        registradores.add(regS7);
        
        // Registrador $t8 25.
        String[] regT8 = {"$t8","11000"};
        registradores.add(regT8);
        
        // Registrador $t9 26.
        String[] regT9 = {"$t9","11001"};
        registradores.add(regT9);
        
        // Registrador $k0 26.
        String[] regK0 = {"$k0","11010"};
        registradores.add(regK0);
        
        // Registrador $k1 27.
        String[] regK1 = {"$k1","11011"};
        registradores.add(regK1);
        
        // Registrador $gp 28.
        String[] regGP = {"$gp","11100"};
        registradores.add(regGP);
        
        // Registrador $sp 29.
        String[] regSP = {"$sp","11101"};
        registradores.add(regSP);
        
        // Registrador $fp 30.
        String[] regFP = {"$fp","11110"};
        registradores.add(regFP);
        
        // Registrador $ra 31.
        String[] regRA = {"$ra","11111"};
        registradores.add(regRA);

    }   
    
} // Fim da classe.
